package com.shengcheng.service.impl;

import com.alibaba.fastjson.JSON;
import com.shengcheng.AccountFeignClient;
import com.shengcheng.OrderFeignClient;
import com.shengcheng.UserFeignClient;
import com.shengcheng.config.WxConfig;
import com.shengcheng.constant.KafkaConstant;
import com.shengcheng.constant.SystemConstant;
import com.shengcheng.entity.OrderInfo;
import com.shengcheng.entity.PaymentInfo;
import com.shengcheng.entity.RechargeInfo;
import com.shengcheng.execption.GuiguException;
import com.shengcheng.mapper.PaymentInfoMapper;
import com.shengcheng.result.RetVal;
import com.shengcheng.service.KafkaService;
import com.shengcheng.service.PaymentInfoService;
import com.shengcheng.util.AuthContextHolder;
import com.shengcheng.utils.MyRequestUtils;
import com.shengcheng.vo.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.model.Transaction;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * 付款信息表 服务实现类
 * </p>
 *
 * @author 强哥
 * @since 2023-12-19
 */
@Service
public class PaymentInfoServiceImpl extends ServiceImpl<PaymentInfoMapper, PaymentInfo> implements PaymentInfoService {
    @Autowired
    private RSAAutoCertificateConfig config;
    @Autowired
    private WxConfig wxConfig;
    @Autowired
    private UserFeignClient userFeignClient;
    @Autowired
    private PaymentInfoService paymentInfoService;
    @Autowired
    private OrderFeignClient orderFeignClient;

    @Override
    public RetVal<Map<String, Object>> saveOrderAndDetail(String paymentType, String orderNo) {
        try {
            //1.保存一份支付记录-防止扯皮
            PaymentInfo paymentInfo = paymentInfoService.savePaymentInfo(paymentType, orderNo);
            JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
            //2.跟之前下单示例一样，填充预下单参数
            PrepayRequest request = new PrepayRequest();
            Amount amount = new Amount();
            amount.setTotal(1);
            request.setAmount(amount);
            request.setAppid(wxConfig.getAppid());
            request.setMchid(wxConfig.getMerchantId());
            request.setDescription(paymentInfo.getContent());
            request.setNotifyUrl(wxConfig.getNotifyUrl());
            request.setOutTradeNo(orderNo);
            //3.获取用户信息
            Long userId = AuthContextHolder.getUserId();
            UserInfoVo userInfoVo = userFeignClient.getUserById(userId).getData();
            Payer payer = new Payer();
            payer.setOpenid(userInfoVo.getWxOpenId());
            request.setPayer(payer);
            //4.response包含了调起支付所需的所有参数，可直接用于前端调起支付
            PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
            //5.从response中获取页面需要的内容返回给前端
            Map<String, Object> result = new HashMap<>();
            result.put("timeStamp", response.getTimeStamp());
            result.put("nonceStr", response.getNonceStr());
            result.put("package", response.getPackageVal());
            result.put("signType", response.getSignType());
            result.put("paySign", response.getPaySign());
            return RetVal.ok(result);
        } catch (Exception e) {
            e.printStackTrace();
            throw new GuiguException(201, e.getMessage());
        }
    }

    @Autowired
    private AccountFeignClient accountFeignClient;
    @Override
    public PaymentInfo savePaymentInfo(String paymentType, String orderNo) {
        PaymentInfo paymentInfo = getOne(new LambdaQueryWrapper<PaymentInfo>().eq(PaymentInfo::getOrderNo,orderNo));
        if(paymentInfo==null){
            paymentInfo=new PaymentInfo();
            //支付订单
            if (paymentType.equals(SystemConstant.PAY_ORDER)) {
                OrderInfo orderInfo = orderFeignClient.getOrderInfo(orderNo).getData();
                paymentInfo.setUserId(orderInfo.getUserId());
                paymentInfo.setContent(orderInfo.getOrderTitle());
                paymentInfo.setAmount(orderInfo.getOrderAmount());
            }else{
                //充值
                RechargeInfo rechargeInfo = accountFeignClient.getRechargeInfo(orderNo).getData();
                paymentInfo.setUserId(rechargeInfo.getUserId());
                paymentInfo.setContent("充值");
                paymentInfo.setAmount(rechargeInfo.getRechargeAmount());
            }
            paymentInfo.setPaymentType(paymentType);
            paymentInfo.setOrderNo(orderNo);
            paymentInfo.setPaymentStatus(SystemConstant.PAYMENT_UNPAID);
            save(paymentInfo);
        }
        return paymentInfo;
    }

    @Override
    public ResponseEntity.BodyBuilder asyncNotify(HttpServletRequest request) {
        //1.获取返回请求的参数
        String wechatPaySerial = request.getHeader("Wechatpay-Serial");
        String wechatpayNonce = request.getHeader("Wechatpay-Nonce");
        String wechatTimestamp = request.getHeader("Wechatpay-Timestamp");
        String wechatSignature = request.getHeader("Wechatpay-Signature");
        String requestBody = MyRequestUtils.readData(request);
        //2.构造RequestParam
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(wechatPaySerial)
                .nonce(wechatpayNonce)
                .signature(wechatSignature)
                .timestamp(wechatTimestamp)
                .body(requestBody)
                .build();

        //3.初始化NotificationParser
        NotificationParser parser = new NotificationParser(config);
        Transaction transaction = parser.parse(requestParam, Transaction.class);
        //4.如果交易成功
        if(transaction!=null&&transaction.getTradeState()== Transaction.TradeStateEnum.SUCCESS){
            //编写自己的业务逻辑
            paymentInfoService.updatePaymentStatus(transaction);
        }
        //5.处理成功，返回200 OK状态码
        return ResponseEntity.status(HttpStatus.OK);
    }
    @Autowired
    private KafkaService kafkaService;


    //分布式事务如何做---已经做好了 用MQ实现最终一致性分布式事务 seata--强一致性分布式事务解决方案
    @Transactional
    @Override
    public void updatePaymentStatus(Transaction transaction) {
        String outTradeNo = transaction.getOutTradeNo();
        PaymentInfo paymentInfo = getOne(new LambdaQueryWrapper<PaymentInfo>().eq(PaymentInfo::getOrderNo,outTradeNo));
        if(paymentInfo.getPaymentStatus()==SystemConstant.PAYMENT_STATUS_PAID){
            return;
        }
        //更新支付信息
        paymentInfo.setPaymentStatus(SystemConstant.PAYMENT_STATUS_PAID);
        paymentInfo.setOutTradeNo(transaction.getTransactionId());
        paymentInfo.setCallbackTime(new Date());
        //防止扯皮
        paymentInfo.setCallbackContent(JSON.toJSONString(transaction));
        updateById(paymentInfo);
        String topic= paymentInfo.getPaymentType().equals(SystemConstant.PAY_ORDER)
                ? KafkaConstant.PAY_ORDER_SUCCESS_QUEUE : KafkaConstant.RECHARGE_SUCCESS_QUEUE;
        kafkaService.sendMessage(topic,paymentInfo.getOrderNo());
    }

    @Override
    public RetVal queryPayStatus(String orderNo) {
        JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
        QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest();
        queryRequest.setMchid(wxConfig.getMerchantId());
        queryRequest.setOutTradeNo(orderNo);
        try {
            Transaction transaction = service.queryOrderByOutTradeNo(queryRequest);
            if(transaction!=null&&transaction.getTradeState()== Transaction.TradeStateEnum.SUCCESS){
                //编写自己的业务逻辑
                paymentInfoService.updatePaymentStatus(transaction);
                return RetVal.ok(true);
            }
        } catch (ServiceException e) {
            // API返回失败, 例如ORDER_NOT_EXISTS
            System.out.printf("code=[%s], message=[%s]\n", e.getErrorCode(), e.getErrorMessage());
            System.out.printf("reponse body=[%s]\n", e.getResponseBody());
        }
        return RetVal.ok(false);
    }
}
